#include <asset/reader/assetreadermesh.h>
#include <fs/fileinfo.h>
#include <gfx/idevice.h>
#include <gfx/iindexbuffer.h>
#include <gfx/ivertexbuffer.h>
#include <gfx/ivertexdeclaration.h>
#include <gfx/mesh.h>
#include <utils/boundingboxbuilder.h>
#include <vfs.h>

ceAssetReaderMesh::ceAssetReaderMesh()
{
}

bool ceAssetReaderMesh::CanRead(ceEngine *engine, ceAssetTypeID type, const ceAssetLocator &locator)
{
	if (type != ceMesh::AssetTypeID)
		{
			return false;
		}

	ceFileInfo fi (locator.GetLocation());

	return fi.GetExtension() == std::string ("mesh");
}

ceRef<ceAsset> ceAssetReaderMesh::Read(ceEngine *engine, ceAssetTypeID type, const ceAssetLocator &locator)
{
	iFile* file = ceVFS::Get()->Open(locator.GetLocation(), OM_Read, TM_Binary);
	if (!file)
		{
			return 0;
		}

	iDevice *device = engine->GetDevice();
	ceMesh* mesh = 0;


	unsigned version;
	file->Read(&version, sizeof (unsigned));
	if (version == 1)
		{
			ceVertexElement vertexElements [] = {
					ceVertexElement(ceProgramParameterName(PPB_Position0), DT_Float, 3, 0,  32, 0),
					ceVertexElement(ceProgramParameterName(PPB_Normal0),   DT_Float, 3, 12, 32, 0),
					ceVertexElement(ceProgramParameterName(PPB_TexCoord0), DT_Float, 2, 24, 32, 0),
					ceVertexElement()
				};
			iVertexDeclaration* vd = device->CreateVertexDeclaration(vertexElements);

			unsigned numVertices = 0;
			file->Read(&numVertices, sizeof (unsigned));

			float *vertices = new float [8 * numVertices];
			file->Read(vertices, sizeof (float) * 8 * numVertices);

			iVertexBuffer* vb = device->CreateVertexBuffer(sizeof(float) * 8 * numVertices, vertices, BDM_Static);
			delete [] vertices;
			vertices = 0;

			unsigned char indexSize = 0;
			file->Read(&indexSize, sizeof (unsigned char));

			unsigned numTrigons = 0;
			file->Read(&numTrigons, sizeof (unsigned));

			iIndexBuffer* ib = 0;
			if (indexSize == 32)
				{
					unsigned *indices = new unsigned [numTrigons * 3];
					file->Read(indices, sizeof (unsigned) * numTrigons * 3);
					ib = device->CreateIndexBuffer(sizeof (unsigned) * numTrigons * 3, indices, BDM_Static);
					delete [] indices;
				}
			else
				{
					unsigned short *indices = new unsigned short [numTrigons * 3];
					file->Read(indices, sizeof(unsigned short) * numTrigons * 3);
					ib = device->CreateIndexBuffer(sizeof (unsigned short) * numTrigons * 3, indices, BDM_Static);
					delete [] indices;
				}

			fflush(stdout);
			ceBoundingBoxBuilder bbBuilder;
			bbBuilder.Initialize(vb, vd);
			ceBoundingBox bbox = bbBuilder.CreateBoundingBox(numVertices);
			bbBuilder.Close();

			mesh = new ceMesh();
      mesh->SetLocator(locator);
			mesh->Set32BitIndices(indexSize == 32);
			mesh->SetLocator(locator);
			mesh->SetNumberOfTrigons(numTrigons);
			mesh->SetPrimitiveType(PT_Triangles);
			mesh->SetVertices(vb);
			mesh->SetVertexDeclaration(vd);
			mesh->SetIndices(ib);
			mesh->SetBoundingBox(bbox);

		}
	file->Close();
	file->Release();

	return mesh;
}
